home *** CD-ROM | disk | FTP | other *** search
Text File | 1995-11-08 | 50.1 KB | 1,470 lines | [TEXT/KAHL] |
- //------------------------- © 1991-1995 by James G. Stout --------------------------
- // File : cdefPopMenu.c
- // Date : September 1,1991
- // Author : Jim Stout
- // Purpose : popup menu cdef
- // : Implements most of the features of the Apple popUpMenu CDEF 63, but
- // : works the same in System 6 & 7 and supports 'mctb' resources.
- // :
- // : This should be "plug compatible" with the Apple CDEF but also has
- // : 7 handy additional variations.
- // :
- // : see cdefPopMenu.h for more detail and variation codes
- // :
- // : If you find a use for this, I'd love to know about it. Bug reports
- // : are always interesting.
- // :
- // : Internet : JimS@WRQ.COM(work hours, PST)
- // : AppleLink : WRQ (daily)
- // : CompuServe : 73240,2052 (weekly or so)
- // : AOL : JasG (weekly or so)
- // : eWorld : Jim Stout (weekly or so)
- //----------------------------------------------------------------------------------
- //#define _DEBUGCDEF 1 // uncomment to do source debugging
-
- // uncomment the following to have the popupInsetFrame variation use the menu's
- // background color instead of the grafPort's background color
-
- //#define USE_PORT_BG
-
- #include "fatCDEF.h"
-
- #include <Controls.h>
- #include <GestaltEqu.h>
- #include <Icons.h>
- #include <LowMem.h>
- #include <Memory.h>
- #include <Palettes.h>
- #ifdef __powerc
- #include <MixedMode.h>
- #endif
- #include <Resources.h>
- #include <ToolUtils.h>
- #include <Traps.h>
- #include <Types.h>
-
- #include "colorCDEF.h"
- #include "miscCDEF.h"
- #include "cdefPopMenu.h"
-
- //----------------------------------------------------------------------------------
- // CDEF globals
- //----------------------------------------------------------------------------------
-
- short gMenuW;
- UniversalProcPtr CalcMenuSizeUPP;
-
- //----------------------------------------------------------------------------------
- // need to patch the CalcMenuSize trap
- //----------------------------------------------------------------------------------
- typedef pascal void ( *CMSFuncPtr ) ( MenuHandle theMenu );
- #define CallCalcMenuSize(theMenu) (*(CMSFuncPtr)CalcMenuSizeUPP)( theMenu );
-
- //----------------------------------------------------------------------------------
- #if _DEBUGCDEF
- pascal long CDmain (short varCode, ControlHandle theCtl, short message, long param);
-
- pascal long CDmain (short varCode, ControlHandle theCtl, short message, long param)
- #else
-
- //==================================================================================
- // Main entry point for the CDEF
- //==================================================================================
-
- pascal long main (short varCode, ControlHandle theCtl, short message, long param)
- #endif
- {
- long ret = 0;
- Point mPt;
- popUpPrivateDataH pd;
- SignedByte cState, dState;
-
- #include "fatEntry.c"
-
- cState = HGetState((Handle)theCtl);
- HLock((Handle)theCtl);
- if((**theCtl).contrlData) {
- dState = HGetState((**theCtl).contrlData);
- HLock((**theCtl).contrlData);
- pd = (popUpPrivateDataH)(*theCtl)->contrlData;
- }
-
- switch(message) {
- case initCntl:
- doInit(theCtl, varCode);
- if((**theCtl).contrlData) {
- dState = HGetState((**theCtl).contrlData);
- HLock((**theCtl).contrlData);
- }
- break;
- case dispCntl:
- doDisp(theCtl, varCode);
- break;
- case drawCntl:
- if((**theCtl).contrlVis != 0 &&
- ((WindowPeek)(**theCtl).contrlOwner)->visible)
- doDraw(theCtl,varCode);
- break;
- case autoTrack:
- doPopUp(theCtl,varCode);
- break;
- case testCntl:
- mPt.v=HiWord(param);
- mPt.h=LoWord(param);
- if(PtInRect(mPt,&(*pd)->rItem) || PtInRect(mPt,&(*pd)->rTitle))
- ret = 1L;
- break;
- case calcCRgns:
- RectRgn((RgnHandle)(param & 0x7fffffffL), &(*theCtl)->contrlRect);
- break;
- case calcCntlRgn:
- case calcThumbRgn:
- RectRgn((RgnHandle)(param), &(*theCtl)->contrlRect);
- break;
- }
-
- if((**theCtl).contrlData)
- HSetState((**theCtl).contrlData, dState);
- HSetState((Handle)theCtl, cState);
-
- #include "fatExit.c"
-
- return(ret);
- }
-
- //==================================================================================
- // Initialize our private data
- //==================================================================================
-
- static void doInit(ControlHandle theCtl, short varCode)
- {
- MenuHandle hMenu;
- popUpPrivateDataH pd=0;
- Boolean popAvail;
- GrafPtr thisPort;
-
- GetPort(&thisPort);
-
- //----------------------------------------------------------------------------------
- // create and initialize our private data
- //----------------------------------------------------------------------------------
-
- pd = (popUpPrivateDataH)NewHandle(sizeof(popUpPrivateData));
- if(pd) {
- HLock((Handle)pd);
- (*pd)->mHandle = hMenu = 0;
- popAvail = trapAvailable(_PopUpMenuSelect);
-
- if(popAvail) {
-
- (*pd)->hasColorQD = hasColorQD();
-
- //----------------------------------------------------------------------------------
- // check to see if this control needs to load and release the menu
- //----------------------------------------------------------------------------------
-
- (*pd)->relMenuRes = false; // assume no…
-
- if(varCode & popupUseAddResMenu) { // menu items from resources
- hMenu = GetMenu((*theCtl)->contrlMin); // try to load an existing menu
- if(hMenu == 0L) // nope, create menu for control
- hMenu = NewMenu((*theCtl)->contrlMin,"\p");
- else
- (*pd)->relMenuRes = true;
-
- if(*hMenu != 0L)
- AddResMenu(hMenu,(*theCtl)->contrlRfCon);
- }
- else {
- SetResLoad(false);
- hMenu = (MenuHandle)GetResource('MENU',(*theCtl)->contrlMin);
- SetResLoad(true);
- if(hMenu == 0L) // it's a dynamic menu
- hMenu = GetMHandle((*theCtl)->contrlMin);
- else
- if(*hMenu == 0L) { // empty handle means the
- ReleaseResource((Handle)hMenu); // menu has not been loaded,
- hMenu = GetMenu((*theCtl)->contrlMin);// so load the menu…
- if(hMenu != 0L)
- (*pd)->relMenuRes = true; // and release it too
- }
- }
-
- //----------------------------------------------------------------------------------
- // initialize our stuff
- //----------------------------------------------------------------------------------
- (*pd)->osVers = getOSVers(); // for later reference
- (*pd)->mHandle = hMenu; // handle to menu to pop
- (*pd)->hMenuState = HGetState((Handle)((*pd)->mHandle));
- HNoPurge((Handle)((*pd)->mHandle)); // menus should NEVER be purgeable!
- SetRect(&(*pd)->rItem, 0, 0, 0, 0);
- //----------------------------------------------------------------------------------
- // get the funky template values for later reference
- //----------------------------------------------------------------------------------
-
- (*pd)->mId = (*theCtl)->contrlMin; // menuId
- (*pd)->tJust = (*theCtl)->contrlValue; // title justification
- (*pd)->tWid = (*theCtl)->contrlMax;
- (*pd)->tWid &= 0xFF; // low byte is width for title
- (*pd)->varCode2 = (*theCtl)->contrlMax & 0xFF00;// high byte is extra varCode
-
- (**pd).txFont = thisPort->txFont;
- (**pd).txSize = thisPort->txSize;
-
- (*theCtl)->contrlData = (Handle)pd; // save our private data
-
- //----------------------------------------------------------------------------------
- // then set control template values to some harmless defaults
- //----------------------------------------------------------------------------------
-
- (*theCtl)->contrlMin = 1;
- (*theCtl)->contrlMax = CountMItems(hMenu);
- (*theCtl)->contrlValue = 1;
- (**theCtl).contrlAction = (ControlActionUPP) -1; // use trackControl
- }
- HUnlock((Handle)pd);
- }
- }
-
- //==================================================================================
- // Clean up and dispose of our private data
- //==================================================================================
-
- static void doDisp(ControlHandle theCtl, short varCode)
- {
- popUpPrivateDataH pd;
-
- pd = (popUpPrivateDataH)(*theCtl)->contrlData;
- if(pd) {
- if ((*pd)->mHandle && *(*pd)->mHandle) {
- HSetState((Handle)(*pd)->mHandle, (*pd)->hMenuState);
-
- if((*pd)->varCode2 & popupNoDeleteMenu) {
- DeleteMenu((*(*pd)->mHandle)->menuID);
- }
- if(varCode & popupUseAddResMenu) {
- if((*pd)->mHandle != NULL && (*pd)->relMenuRes) {
- ReleaseResource((Handle)(*pd)->mHandle);
- }
- else {
- DisposeMenu((*pd)->mHandle);
- }
- }
- else {
- if((*pd)->mHandle != NULL && (*pd)->relMenuRes) {
- ReleaseResource((Handle)(*pd)->mHandle);
- }
- }
- }
- HUnlock((Handle)pd);
- DisposHandle((Handle)pd);
- (*theCtl)->contrlData = 0;
- }
- }
-
- //==================================================================================
- // If running with System 7, use DeviceLoop to gracefully handle multiple screens.
- // Simulate DeviceLoop if using System 6...
- //==================================================================================
-
- static void doDraw(ControlHandle theCtl, short varCode)
- {
- devLoopHandle hDl;
- RgnHandle saveClip, hRgn;
- DeviceLoopDrawingUPP drawControlUPP;
-
- //----------------------------------------------------------------------------------
- // Create our data handle to pass to DeviceLoop
- //----------------------------------------------------------------------------------
-
- hDl = (devLoopHandle)NewHandle(sizeof(devLoopData));
- if(hDl) {
- drawControlUPP = NewDeviceLoopDrawingProc(drawControl);
-
- (**hDl).theCtl = theCtl;
- (**hDl).varCode = varCode;
- (**hDl).controlRect = (**theCtl).contrlRect;
-
- //----------------------------------------------------------------------------------
- // Do the clip region properly. Thanks Ari!
- //----------------------------------------------------------------------------------
-
- saveClip = NewRgn();
- GetClip(saveClip);
-
- hRgn = NewRgn();
- RectRgn(hRgn, &(**hDl).controlRect);
- SectRgn(saveClip, hRgn, hRgn);
-
- if(EmptyRgn(hRgn)) { // if empty, don't waste
- DisposeRgn(saveClip); // time drawing...
- DisposeRgn(hRgn);
- return;
- }
-
- //----------------------------------------------------------------------------------
- // Call DeviceLoop to take care of our drawing
- //----------------------------------------------------------------------------------
-
- if(getOSVers() >= 0x0700) {
- DeviceLoop (hRgn, drawControlUPP, (long)hDl, 0);
- }
- else {
- sys6DeviceLoop (hRgn, drawControlUPP, (long)hDl, 0);
- }
-
- SetClip(saveClip);
- DisposeRgn(hRgn);
- DisposeHandle((Handle)hDl);
- DisposeRoutineDescriptor(drawControlUPP);
- }
- }
-
- //==================================================================================
- // Draw the control - using the proper menu colors. The aim here is to draw an
- // exact representation of what the Menu Manager draws for a menu item, but inside
- // a drop-shadowed rectangle. If we don't match what the Menu Mgr draws, the
- // menu item text will shift when the menu is popped.
- //
- // This is called by DeviceLoop, but in this case, we just pay attention to the
- // "depth" and "userData" parameters.
- //==================================================================================
-
- pascal void drawControl (short depth, short dFlags, GDHandle theDevice, long userData)
- {
-
- #pragma unused(dFlags, theDevice)
-
- ControlHandle hCtl;
- short varCode,saveFont,saveSize,saveFace;
- short cntlW,w,len,iconNum,cmdChar;
- long inx;
- Str255 mStr;
- Boolean sysFont,inactive=false,itemDisable=false;
- Boolean inColor=false,bgInColor=false,gotGray=false;
- PenState savePen;
- Rect tempRect;
- Style itemStyle;
- RGBColor saveFore,saveBack,menuFore,menuBack,tempFore;
- RGBColor rgbWhite={-1,-1,-1};
- RGBColor rgbA = {0xAAAA,0xAAAA,0xAAAA};
- GDHandle hThisDevice;
- GrafPtr thisPort;
- popUpPrivateDataH pd;
- devLoopHandle hDl;
-
- //----------------------------------------------------------------------------------
- // Can we draw?
- //----------------------------------------------------------------------------------
-
- hDl = (devLoopHandle)userData; // need control & varCode
- if(hDl) {
- hCtl = (**hDl).theCtl;
- varCode = (**hDl).varCode;
- }
- else
- return;
-
- pd = (popUpPrivateDataH)(*hCtl)->contrlData; // get our private data
- if(!pd) // oops !
- return;
- if(!(*pd)->mHandle) // oops again !
- return;
-
- //----------------------------------------------------------------------------------
- // initialize for drawing - set a few flags & color stuff
- //----------------------------------------------------------------------------------
-
- GetPort(&thisPort);
- if(depth > 1 && !(((CGrafPtr)thisPort)->portVersion & 0x8000))
- depth = 1;
-
- if((*hCtl)->contrlValue < 32) { // is the item disabled?
- inx = 31 - (*hCtl)->contrlValue;
- if(!BitTst(&(**(*pd)->mHandle).enableFlags, inx))
- itemDisable = true;
- }
- if((*hCtl)->contrlHilite == 255) // is the control disabled?
- inactive = itemDisable = true;
-
- if(depth > 2) {
- inColor = true;
- bgInColor = true;
- saveColors(&saveFore,&saveBack); // save current colors
- if(saveBack.red == 65535 && // is bg white?
- saveBack.green == 65535 &&
- saveBack.blue == 65535)
- bgInColor = false;
- }
-
- //----------------------------------------------------------------------------------
- // do font stuff
- //----------------------------------------------------------------------------------
-
- if((thisPort->txFont != (**pd).txFont) || // if font changed,
- (thisPort->txSize != (**pd).txSize)) { // clear rect to erase
- (**pd).txFont = thisPort->txFont; // old font
- (**pd).txSize = thisPort->txSize;
- EraseRect(&(*hCtl)->contrlRect);
- }
-
- sysFont = setFont(thisPort, &saveFont, &saveSize, varCode, (**pd).hasColorQD);
-
- saveFace = thisPort->txFace;
- GetPenState(&savePen);
- PenSize(1,1);
- PenPat( (ConstPatternParam) "\xff\xff\xff\xff\xff\xff\xff\xff");
-
- //----------------------------------------------------------------------------------
- // This is gonna destroy any background PICT, but is necessary because we may have
- // different sized ICONs in the menu.
- //----------------------------------------------------------------------------------
-
- if((*pd)->varCode2 & popupIconOnly) {
- EraseRect(&(*hCtl)->contrlRect);
- }
-
- //----------------------------------------------------------------------------------
- // Get locations and sizes for our drawing - these change based on menu item style
- //----------------------------------------------------------------------------------
-
- tempRect = (*pd)->rItem; // need this below
-
- getRects(hCtl, sysFont);
-
- //----------------------------------------------------------------------------------
- // NOTE: gMenuW is a global that contains a 'calculated' menu width - including
- // the space for the 'popup symbol'. Later, we will use this to fool the Menu
- // Manager into thinking the menu is wider that it really is. See 'myCalcMenuSize'
- // routine below and the patch to CalcMenuSize.
- //
- // This lets the 'popped' menu be the same size as our drawing of the current
- // item + the symbol in rectangle 'rItem'.
- //
- // Rect rItem is adjusted by resizePopup() and will be the correct size for the
- // doPop routine. It is then reset when we enter doDraw after popping the menu.
- //
- // Thanks to Chris Faigle for this technique.
- //----------------------------------------------------------------------------------
-
- CalcMenuSize((*pd)->mHandle);
- gMenuW = (*(*pd)->mHandle)->menuWidth; // normal menu size
-
- if((*pd)->varCode2 & popupIconOnly) {
- if((*pd)->varCode2 & popupInsetFrame) {
- OffsetRect(&(*pd)->rIcon, 1, 0);
- (*pd)->rItem.left+=1;
- (*pd)->rTitle.right = (*pd)->rItem.left;
- }
- (*pd)->rItem.right = (*pd)->rIcon.right + SHADOW; // set rItem to icon width
- }
- else
- if((*pd)->symWid == 0) { // variant without symbol
- cntlW = (*pd)->rItem.right-(*pd)->rItem.left; // so set rItem to size of
- if(gMenuW + SHADOW < cntlW) // menu if needed.
- (*pd)->rItem.right = (*pd)->rItem.left + gMenuW + SHADOW;
- }
- else
- resizePopup(hCtl, varCode); // adjust gMenuW & rItem
-
- //----------------------------------------------------------------------------------
- // Now tempRect contains the rect for the previous menu item - adjusted to the
- // proper width. Use to erase the control rect. Doing it this way is really only
- // important if the menu is using styled text.
- //----------------------------------------------------------------------------------
-
- tempRect.right = (*pd)->rItem.right;
- EraseRect(&tempRect);
-
- //----------------------------------------------------------------------------------
- // set colors for drawing
- //----------------------------------------------------------------------------------
-
- if (inColor) {
- hThisDevice = GetGDevice();
- if(inactive && (*pd)->osVers >= 0x0700) { // inactive and System 7
- GetForeColor(&menuFore); // gray out the popup
- GetBackColor(&menuBack); // the Sys 7 way
- gotGray = GetGray(hThisDevice,&menuBack,&menuFore);
- if(gotGray)
- RGBForeColor(&menuFore); // gray for title & frame
- }
- }
-
- //----------------------------------------------------------------------------------
- // draw title, if requested
- //----------------------------------------------------------------------------------
-
- if((*pd)->tWid > 0) { // 0 means no title
- itemStyle = (*pd)->tJust >> 8;
- TextFace(itemStyle);
- #ifdef _REALOBSCUREBUG
- //
- // if itemStyle is outline, then the control title should be 1 pixel lower
- // than for other styles. I don't know why... If you need this, #define it...
- //
- GetItemStyle((*pd)->mHandle, (*hCtl)->contrlValue, &itemStyle);
- if(itemStyle & outline)
- (*pd)->vDraw+=1;
- #endif
- if(inColor && depth > 2) {
- GetForeColor(&tempFore); // save this for later
- if(bgInColor && (varCode & ctl3D)) { // draw embossed title
- RGBForeColor(&rgbWhite);
- MoveTo((*pd)->hTitle+1,(*pd)->vDraw+1);
- DrawString((*hCtl)->contrlTitle);
-
- }
- setPartColor(hCtl, cTextColor, true); // set text color
- }
- if(gotGray) // inactive and System 7
- TextMode(grayishTextOr); // so draw in gray
-
- MoveTo((*pd)->hTitle,(*pd)->vDraw); // draw title string here
- DrawString((*hCtl)->contrlTitle); // draw it
-
- if(inColor)
- RGBForeColor(&tempFore); // back to port foreColor
- TextMode(srcOr);
- #ifdef _REALOBSCUREBUG
- //
- // have to readjust, since the menu item draws as calcuated
- //
- if(itemStyle & outline)
- (*pd)->vDraw-=1;
- #endif
- }
-
- //----------------------------------------------------------------------------------
- // now, do the drawing of the 'popup' frame
- //----------------------------------------------------------------------------------
-
- tempRect = (*pd)->rItem;
- if((*pd)->varCode2 & popupIconOnly) { // shrink frame a bit so
- tempRect.top = (*pd)->rIcon.top-2; // it just fits icon
- tempRect.bottom = (*pd)->rIcon.bottom+2;
- }
- else
- tempRect.bottom-=1; // inset past the
- tempRect.right-=1; // drop shadow
-
- if(((*pd)->varCode2 & popupInsetFrame) ) { // Draw an inset popup
- if(inColor) {
- FrameRect(&tempRect); // popUp Menu frame
- RGBForeColor(&rgbA);
- MoveTo(tempRect.left-1,tempRect.bottom);
- LineTo(tempRect.left-1,tempRect.top-1);
- LineTo(tempRect.right-1,tempRect.top-1);
- ForeColor(whiteColor);
- Move(1,0);
- LineTo(tempRect.right,tempRect.bottom);
- LineTo(tempRect.left,tempRect.bottom);
- }
- else
- drawPopupFrame(&tempRect);
- }
- else // Draw the normal
- drawPopupFrame(&tempRect); // popUp Menu frame
-
- InsetRect(&tempRect,1,1); // the interior of popup
-
-
- //----------------------------------------------------------------------------------
- // now, draw item string. Get menu colors & check to see if we need to draw in gray
- //----------------------------------------------------------------------------------
-
- if (inColor) {
- getMenuColors((*pd)->mId,(*hCtl)->contrlValue, // get the menu colors
- &menuFore,&menuBack);
- RGBForeColor(&menuFore);
- #ifdef USE_PORT_BG
- if(!((*pd)->varCode2 & popupInsetFrame)) // don't use menu bg color
- #endif
- RGBBackColor(&menuBack); // if inset frame
-
- GetForeColor(&tempFore);
- if((*pd)->osVers >= 0x0700 && // GetGray can be called
- (inactive || itemDisable)) { // to get "inactive" gray
- // used for System 7
-
- gotGray = GetGray(hThisDevice,&menuBack,&tempFore);
- if(gotGray)
- RGBForeColor(&tempFore); // set gray for string
- }
- }
- PenPat( (ConstPatternParam) "\x00\x00\x00\x00\x00\x00\x00\x00");
- PaintRect(&tempRect); // erase to bg color
- PenPat( (ConstPatternParam) "\xff\xff\xff\xff\xff\xff\xff\xff");
-
- //----------------------------------------------------------------------------------
- // Truncate the item string if needed. Must fit available control width,
- // which includes some leading space and the symbol space on the right.
- //----------------------------------------------------------------------------------
-
- if(!((*pd)->varCode2 & popupSymbolOnly)) {
- GetItemStyle((*pd)->mHandle, (*hCtl)->contrlValue, &itemStyle);
- TextFace(itemStyle);
- GetItem((MenuHandle)(*pd)->mHandle, // get menu item string
- (*hCtl)->contrlValue,mStr);
-
- w = StringWidth(mStr); // get its width
-
- if((*pd)->varCode2 & popupCenterText) { // center text in control
- cntlW = tempRect.right-tempRect.left;
- (*pd)->hItem = tempRect.left + (cntlW - w)/2 +1;
- }
- else { // draw in normal, menu
- cntlW = tempRect.right - // position but truncate
- (*pd)->hItem - (*pd)->symWid; // string if too wide.
-
- if(cntlW > 0 && mStr[0] > 1) { // truncate the string
- while(w > cntlW) {
- len = mStr[0]-1;
- if(len < 1) // no endless loops needed
- break;
- mStr[0] = len;
- if(len > 1)
- mStr[len] = ELLIPSIS;
- w = StringWidth(mStr);
- };
- }
- }
- //----------------------------------------------------------------------------------
- // now go ahead and draw the current menu item string, in 3D if needed.
- //----------------------------------------------------------------------------------
- if(bgInColor && (varCode & ctl3D) && ((*pd)->varCode2 & popupInsetFrame)) {
- MoveTo((*pd)->hItem+1, (*pd)->vDraw+1);
- GetForeColor(&tempFore);
- RGBForeColor(&rgbWhite);
- DrawString(mStr);
- RGBForeColor(&tempFore);
- }
- MoveTo((*pd)->hItem, (*pd)->vDraw);
- DrawString(mStr);
- }
-
- //----------------------------------------------------------------------------------
- // draw the popUp symbol
- //---------------------------------------------------------------------------------
-
- if((*pd)->symWid > 0) {
- if(inColor) {
- if((*pd)->varCode2 & popupBlackSymbol) {
- ForeColor(blackColor);
- if(inactive && gotGray) { // did this before
- GetForeColor(&tempFore);
- if(GetGray(hThisDevice,&menuBack,&tempFore))
- RGBForeColor(&tempFore); // set gray for symbol
- }
- }
- else
- if(!inactive)
- RGBForeColor(&menuFore);
- }
- drawSymbol(tempRect,(*pd)->symHt, (*pd)->symWid);
- }
- //----------------------------------------------------------------------------------
- // draw icon
- //----------------------------------------------------------------------------------
-
- GetItemIcon((MenuHandle)(*pd)->mHandle, // is there an icon ?
- (*hCtl)->contrlValue, &iconNum);
- if(iconNum) {
- GetItemCmd((MenuHandle)(*pd)->mHandle, // what kind?
- (*hCtl)->contrlValue, &cmdChar);
- plotAnIcon(iconNum, &(*pd)->rIcon, (*pd)->osVers,
- cmdChar, itemDisable, (*pd)->hasColorQD, inColor);
- }
- //----------------------------------------------------------------------------------
- // draw the inactive version - this gets a little complicated when in color and
- // with System 7 - we may have sucessfully drawn the title in gray, but not the
- // menu text - if the menu bg was colored but the dialog wasn't...
- //----------------------------------------------------------------------------------
-
- if((inactive || itemDisable) && !gotGray) { // new style graying failed
- PenPat( (ConstPatternParam) "\xAA\x55\xAA\x55\xAA\x55\xAA\x55");
- if(inColor && (*pd)->osVers >= 0x0700)
- PenMode(notSrcBic);
- else
- PenMode(patBic);
-
- //----------------------------------------------------------------------------------
- // if entire control is disabled, make frame gray, otherwise, just the item string
- //----------------------------------------------------------------------------------
-
- if(inactive) { // expand rect to include
- InsetRect(&tempRect,-1,-1); // frame & drop shadow
- tempRect.bottom+=1;
- tempRect.right+=1;
- }
- else
- if(itemDisable) {
- tempRect.right-= (*pd)->symWid; // don't gray the symbol
- }
-
- PaintRect(&tempRect); // now it is gray
-
- if(inColor)
- restoreColors(&saveFore,&saveBack);
-
- //----------------------------------------------------------------------------------
- // if entire control is disabled, make title gray
- //----------------------------------------------------------------------------------
-
- if(inactive)
- PaintRect(&(*pd)->rTitle);
- }
-
- //----------------------------------------------------------------------------------
- // all done. Restore colors and font.
- //----------------------------------------------------------------------------------
- if(inColor)
- restoreColors(&saveFore, &saveBack);
- SetPenState(&savePen);
- TextFace(saveFace);
- restoreFont(thisPort, saveFont, saveSize, varCode);
- }
-
- //==================================================================================
- // Pop the menu and invert the title of the control
- //==================================================================================
-
- static void doPopUp(ControlHandle hCtl, short varCode)
- {
- short saveFont,saveSize,saveFace,pixDepth,newItem=0;
- Point popPt;
- Style itemStyle;
- GrafPtr thisPort;
- RGBColor saveFore,saveBack,menuFore,menuBack;
- popUpPrivateDataH pd;
-
- pd = (popUpPrivateDataH)(*hCtl)->contrlData;
- if(!pd) // oops !
- return;
-
- if(!(*pd)->mHandle) // oops again !
- return;
-
- pixDepth = getPixDepth(&(*hCtl)->contrlRect); // in color?
-
- //----------------------------------------------------------------------------------
- // add menu to menulist
- //----------------------------------------------------------------------------------
-
- InsertMenu((*pd)->mHandle,-1);
-
- //----------------------------------------------------------------------------------
- // Note: To "fool" the Menu Manager into drawing with the Window Font & size
- // instead of the System Font & size, the setFont() routine sets the global
- // LastSpExtra to -1 to force a rebuild of the font cache.
- //
- // This MUST be done after calling InsertMenu and before calling DeleteMenu,
- // or we will have a VERY funny looking menubar in the calling application.
- //----------------------------------------------------------------------------------
-
- GetPort(&thisPort);
- setFont(thisPort, &saveFont, &saveSize, varCode, (*pd)->hasColorQD); // do AFTER InsertMenu!
- CalcMenuSize((*pd)->mHandle);
-
- //----------------------------------------------------------------------------------
- // Make sure we patch the menu to the correct width.
- // See note above about gMenuW global
- //----------------------------------------------------------------------------------
-
- (*pd)->rItem.right-=SHADOW; // a little "fixup"
- if((*pd)->symWid == 0) // leave width alone
- gMenuW = (*(*pd)->mHandle)->menuWidth;
- else // expand to include symbol
- resizePopup(hCtl, varCode); // adjust gMenuW & rItem
-
- if(gMenuW < (**(*pd)->mHandle).menuWidth) // never size the menu
- gMenuW = (**(*pd)->mHandle).menuWidth; // in our patch to a width
- // less than real width.
-
- (**(*pd)->mHandle).menuWidth = gMenuW; // This needed for System 6
-
- //----------------------------------------------------------------------------------
- // set item mark before we 'pop' menu menu
- //----------------------------------------------------------------------------------
-
- if(!((*pd)->varCode2 & popupNoMark)) {
- if((varCode & popupUseWFont) && (thisPort->txFont != systemFont))
- SetItemMark((*pd)->mHandle,(*hCtl)->contrlValue, DOT);
- else
- SetItemMark((*pd)->mHandle,(*hCtl)->contrlValue, CHECKMARK);
- }
-
- //----------------------------------------------------------------------------------
- // draw title, if requested, but invert the colors…
- //----------------------------------------------------------------------------------
-
- if((*pd)->varCode2 & popupInsetFrame && pixDepth > 2)
- EraseRect(&(*hCtl)->contrlRect); // remove top/left shadow
-
- if((*pd)->tWid > 0) { // is there a title?
- if (pixDepth > 2) { // in color ?
- getMenuColors((*pd)->mId, (*hCtl)->contrlValue,
- &menuFore, &menuBack); // draw an inverted title
- saveColors(&saveFore,&saveBack);
- RGBForeColor(&menuBack); // N.B ! these are reversed
- RGBBackColor(&menuFore);
-
- saveFace = thisPort->txFace;
- itemStyle = (*pd)->tJust >> 8;
- TextFace(itemStyle);
-
- PenPat( (ConstPatternParam) "\x00\x00\x00\x00\x00\x00\x00\x00");
- PaintRect(&(*pd)->rTitle); // erase title rect
- PenPat( (ConstPatternParam) "\xff\xff\xff\xff\xff\xff\xff\xff");
- #ifdef _REALOBSCUREBUG
- GetItemStyle((*pd)->mHandle, (*hCtl)->contrlValue, &itemStyle);
- if(itemStyle & outline)
- (*pd)->vDraw+=1;
- #endif
- MoveTo((*pd)->hTitle,(*pd)->vDraw);
- DrawString((*hCtl)->contrlTitle);
-
- restoreColors(&saveFore,&saveBack);
- TextFace(saveFace);
- }
- else {
- InvertRect(&(*pd)->rTitle);
- }
- }
-
- //----------------------------------------------------------------------------------
- // get ready to pop the menu
- //----------------------------------------------------------------------------------
-
- popPt.h = (*pd)->rItem.left+1; // position for pop-up
- popPt.v = (*pd)->rItem.top+1;
- LocalToGlobal(&popPt); // convert to global coords
-
- patchCalcMenuSize(true); // install our patch
-
- #ifdef THINK_C
- RememberA4();
- #endif
-
- //----------------------------------------------------------------------------------
- // now we can pop the menu
- //----------------------------------------------------------------------------------
-
- newItem = PopUpMenuSelect((*pd)->mHandle,popPt.v,popPt.h,(*hCtl)->contrlValue);
-
- //----------------------------------------------------------------------------------
- // now clear item mark, set controlValue, cleanup and exit
- //----------------------------------------------------------------------------------
-
- patchCalcMenuSize(false); // remove our patch
-
- SetItemMark((*pd)->mHandle,(*hCtl)->contrlValue, noMark);
-
- if(newItem != 0) { // anything chosen ?
- (*hCtl)->contrlValue = newItem; // set new control value
- }
- restoreFont(thisPort, saveFont, saveSize, varCode); // do BEFORE DeleteMenu()!!
-
- (*hCtl)->contrlMax = CountMItems((*pd)->mHandle); // new items??
-
- //----------------------------------------------------------------------------------
- // Remove menu from menu list and restore colors
- //----------------------------------------------------------------------------------
-
- if((*(*pd)->mHandle)->menuID > 0 &&
- !((*pd)->varCode2 & popupNoDeleteMenu)) {
- DeleteMenu((*(*pd)->mHandle)->menuID); // trashes the 'mctb' too
- if (pixDepth > 1)
- setMenuColors((*(*pd)->mHandle)->menuID); // need 'em in doDraw
- }
-
- EraseRect(&(*pd)->rTitle); // clear inverted title
- }
-
- //==================================================================================
- // Draw the popup symbol - a downward pointing triangle
- //==================================================================================
-
- static void drawSymbol(Rect r, short symHt, short symWid)
- {
- short inx,wid,inset;
-
- wid = symHt*2-2;
- inx = (r.right - r.left)-6;
- if(symWid && inx > symWid) // center in rect if needed
- inset = 6;
- else
- inset = ((r.right - r.left) - wid)/2+1; // for compatibility with CDEF 63
-
- MoveTo(r.right - wid - inset, r.top+((r.bottom-r.top) - symHt)/2);
- for(inx=1;inx<=symHt;inx++) {
- Line(wid,0);
- Move(-wid+1,+1);
- wid-=2;
- }
- }
- //==================================================================================
- // Draw the normal, drop shadowed popup
- //==================================================================================
-
- static void drawPopupFrame(Rect * r)
- {
- FrameRect(r); // popUp Menu frame
- MoveTo((*r).left+SHADOW,(*r).bottom); // do a drop shadow
- LineTo((*r).right,(*r).bottom); // along bottom edge…
- LineTo((*r).right,(*r).top+SHADOW); // and along right edge…
- }
- //==================================================================================
- // Calculate various Rects used in drawing.
- // This is key to the whole CDEF - we must draw the popup in the same location
- // as the Menu Manager will when we pop the menu. If we don't line things up
- // exactly, the item text and icon will 'shift' when we pop the menu.
- //==================================================================================
-
- static void getRects(ControlHandle hCtl, Boolean sysFont)
- {
- short wid,ht,fHt;
- short vOff,iconNum=0,iconWid,iconHt,cmdChar;
- Style itemStyle,titleStyle;
- unsigned char tJust;
- FontInfo fInfo;
- Rect rTemp;
- popUpPrivateDataH pd;
-
- pd = (popUpPrivateDataH)(*hCtl)->contrlData;
-
- if(!pd) // oops !
- return;
-
- //----------------------------------------------------------------------------------
- // If we will draw more than the symbol, check for icon
- //----------------------------------------------------------------------------------
-
- GetItemCmd((*pd)->mHandle, (*hCtl)->contrlValue, &cmdChar);
- if(cmdChar != 0x1C)
- GetItemIcon((*pd)->mHandle, (*hCtl)->contrlValue, &iconNum);
-
- //----------------------------------------------------------------------------------
- // get font metrics
- //----------------------------------------------------------------------------------
-
- GetItemStyle((*pd)->mHandle, (*hCtl)->contrlValue, &itemStyle);
- TextFace(itemStyle);
-
- GetFontInfo(&fInfo);
- ht = fInfo.ascent+fInfo.descent+fInfo.leading; // height of menu item
-
- TextFace(normal);
- GetFontInfo(&fInfo);
- fHt = fInfo.ascent+fInfo.descent+fInfo.leading;
- if(sysFont)
- fInfo.widMax-=2; // System MDEF fudges this
- fInfo.widMax+=3; // and we fudge again…
- //----------------------------------------------------------------------------------
- // make adjustments for icon items if needed
- //----------------------------------------------------------------------------------
- if(iconNum) {
- SetRect(&rTemp, 0, 0, 32, 32); // b&w icon always 32x32
- switch(cmdChar) {
- case 0x1D: // reduced icon, 'ICON' or 'cicn'
- case 0x1E: // small icon 'SICN'
- iconWid = iconHt = 16;
- break;
- case 0:
- getIconSize(iconNum, &rTemp);
- iconWid = rTemp.right - rTemp.left;
- iconHt = rTemp.bottom- rTemp.top;
- break;
- }
- if(iconHt + 2 >= ht)
- ht = iconHt + 2;
- }
-
- //----------------------------------------------------------------------------------
- // calculate title rect
- //----------------------------------------------------------------------------------
-
- (*pd)->rTitle = (*hCtl)->contrlRect; // title rect
- (*pd)->rTitle.right = (*pd)->rTitle.left + (*pd)->tWid; // width for title string
- (*pd)->rTitle.top = (*pd)->rTitle.bottom - ht; // height matches menu hilite
-
- OffsetRect(&(*pd)->rTitle, 0, -2); // adjust for drop shadow
-
- //----------------------------------------------------------------------------------
- // calcuate item rect
- //----------------------------------------------------------------------------------
-
- (*pd)->rItem = (*hCtl)->contrlRect; // popup rect
-
- if((*pd)->rItem.top < (*pd)->rItem.bottom - (ht+SHADOW))
- (*pd)->rItem.top = (*pd)->rItem.bottom - (ht+SHADOW);
-
- (*pd)->rItem.left = (*pd)->rTitle.right;
-
- //----------------------------------------------------------------------------------
- // Center the item & title rects in the control rect and calcuate text draw points
- //----------------------------------------------------------------------------------
-
- vOff = (((*hCtl)->contrlRect.bottom-(*hCtl)->contrlRect.top) -
- ((*pd)->rItem.bottom-(*pd)->rItem.top))/2;
-
- OffsetRect(&(*pd)->rItem, 0, -vOff);
- OffsetRect(&(*pd)->rTitle, 0, -vOff);
-
- (*pd)->vDraw = (*pd)->rItem.top+fInfo.ascent + 1; // save draw points
- (*pd)->hItem = (*pd)->rItem.left+fInfo.widMax;
-
- //----------------------------------------------------------------------------------
- // calculate icon rect & item draw point
- //----------------------------------------------------------------------------------
-
- if(iconNum) {
- (*pd)->rIcon = (*pd)->rTitle;
- (*pd)->rIcon.bottom = (*pd)->rIcon.top + iconHt;
- vOff = (ht+1-iconHt)/2; // center icon in
- OffsetRect(&(*pd)->rIcon, 0, vOff); // item rect
-
- if((*pd)->varCode2 & popupIconOnly)
- (*pd)->rIcon.left = (*pd)->rTitle.right + 2; // skip item text inset
- else
- (*pd)->rIcon.left = (*pd)->rTitle.right + fInfo.widMax;
-
- (*pd)->rIcon.right = (*pd)->rIcon.left + iconWid;
-
- //----------------------------------------------------------------------------------
- // now, adjust the draw point for the item text string
- //----------------------------------------------------------------------------------
-
- if(iconHt >= fHt)
- (*pd)->vDraw = (*pd)->vDraw + (iconHt - fHt)/2 + 1;
-
- (*pd)->hItem = (*pd)->hItem + iconWid + CharWidth(0x20);
- }
-
- //----------------------------------------------------------------------------------
- // calculate size of popup symbol - menu will be wider by this amount
- //----------------------------------------------------------------------------------
-
- if(((*pd)->varCode2 & popupNoSymbol) || // don't need extra space.
- ((*pd)->varCode2 & popupIconOnly) ||
- ((*pd)->varCode2 & popupCenterText))
- (*pd)->symWid = 0;
- else {
- (*pd)->symHt = fHt/3 + 1; // height of symbol
- (*pd)->symWid = (*pd)->symHt * 2 + fHt/3; // this is exact for Chi 12
- // and close for all others.
-
- if((*pd)->varCode2 & popupSymbolOnly) { // Adjust rect for symbol
- if((*pd)->tWid == 0)
- (*pd)->rItem.left+=1;
- (*pd)->rItem.right = (*pd)->rItem.left + // only menus.
- (*pd)->symHt*2 + 12; // 6 pixel "border"
- }
- else { // compatible with CDEF 63
- wid = (*hCtl)->contrlRect.right -
- (*hCtl)->contrlRect.left-1; // controls that are very
- if(wid <= (*pd)->symWid) { // narrow.
- (*pd)->symWid = 0; // don't expand width.
- }
- }
- }
-
- //----------------------------------------------------------------------------------
- // calculate title string justification
- //----------------------------------------------------------------------------------
-
- if((*pd)->tWid) { // we have a title string
- tJust = (*pd)->tJust & 0xff; // get title justification
-
- titleStyle = (*pd)->tJust >> 8; // get title style
- TextFace(titleStyle);
-
- if((*pd)->tWid > 0) { // horiz coord from tJust
- wid = StringWidth((*hCtl)->contrlTitle);
- if (tJust == popupTitleRightJust)
- (*pd)->hTitle = (*pd)->rTitle.right - wid - 3;
- else
- if (tJust == popupTitleCenterJust)
- (*pd)->hTitle = (*pd)->rTitle.left +
- (((*pd)->rTitle.right - (*pd)->rTitle.left) - wid)/2;
- else
- (*pd)->hTitle = (*pd)->rTitle.left+4; // left justified (+4)
- }
- }
-
- //----------------------------------------------------------------------------------
- // System 6 MDEF draws a little differently with an ICON
- //----------------------------------------------------------------------------------
-
- if((*pd)->osVers < 0x0700 && iconNum > 0) {
- OffsetRect(&(*pd)->rIcon, 0, 1);
- (*pd)->rItem.bottom++;
- (*pd)->rTitle.bottom+=2;
- (*pd)->vDraw++;
- }
-
- }
-
- //==================================================================================
- // Resize the menu and the controlRect if needed. This is called from our
- // doDraw routine and from the doPopUp routine. The doPopUp routine will
- // insure that gMenuW is at least as wide as the normal menu.
- //
- // Rules are:
- // 1. gMenuW cannot be wider than the control.
- // 2. If popupFixedWidth, gMenuW must equal control width.
- // 2. If not popupFixedWidth, control rect must shrink to fit menu width.
- //==================================================================================
-
- static void resizePopup(ControlHandle hCtl, short varCode)
- {
- short cntlW;
- popUpPrivateDataH pd;
-
- pd = (popUpPrivateDataH)(*hCtl)->contrlData;
-
- cntlW = (*pd)->rItem.right - (*pd)->rItem.left; // width of control
-
- gMenuW = (**(*pd)->mHandle).menuWidth + // width of menu plus
- (*pd)->symWid; // symbol width
-
- if(gMenuW > cntlW) // limit menu to the
- gMenuW = cntlW; // control width
- else {
- if(varCode & popupFixedWidth) // expand menu to the
- gMenuW = cntlW; // control width
- else // shrink item rect
- (*pd)->rItem.right = (*pd)->rItem.left + gMenuW;
- }
- }
-
- //==================================================================================
- // widen the menu to allow for the "popUp" symbol width
- //==================================================================================
-
- #ifdef __powerc
- enum {
- uppCalcMenuSizeInfo= kPascalStackBased
- | RESULT_SIZE(SIZE_CODE(sizeof(0)))
- | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(Handle)))
- };
- #endif
-
- static pascal void myCalcMenuSize(MenuHandle hMenu)
- {
-
- #ifdef __powerc
-
- CallUniversalProc(CalcMenuSizeUPP, uppCalcMenuSizeInfo, hMenu);
- (**hMenu).menuWidth = gMenuW; // Replace the menuWidth with new value
-
- #endif
-
- #ifdef THINK_C
-
- SetUpA4(); // Restore A4 world so we can use our globals
- CallCalcMenuSize( hMenu ); // Call the real CalcMenuSize
- (**hMenu).menuWidth = gMenuW; // Replace the menuWidth with new value
- RestoreA4();
-
- #endif
-
- #ifndef __powerc
- #ifdef __MWERKS__
- long oldA4;
-
- oldA4 = SetCurrentA4();
- CallCalcMenuSize(hMenu);
- (**hMenu).menuWidth = gMenuW; // Replace the menuWidth with new value
- SetA4(oldA4);
-
- #endif
- #endif
- }
-
- //==================================================================================
- // Patch the CalcMenus trap so we can adjust the width of the menu
- //==================================================================================
-
- static void patchCalcMenuSize(short patch)
- {
-
- #ifdef __powerc
- THz saveZone;
- UniversalProcPtr myCalcMenuSizeUPP;
-
- saveZone = GetZone();
- SetZone(SystemZone());
-
- if(patch) {
- CalcMenuSizeUPP = NGetTrapAddress(_CalcMenuSize,ToolTrap);
- myCalcMenuSizeUPP = NewRoutineDescriptor (
- (ProcPtr) myCalcMenuSize,
- uppCalcMenuSizeInfo,
- GetCurrentISA());
- NSetTrapAddress((UniversalProcPtr)myCalcMenuSizeUPP,_CalcMenuSize,ToolTrap);
-
- }
- else {
- NSetTrapAddress(CalcMenuSizeUPP,_CalcMenuSize,ToolTrap);
- }
-
- SetZone(saveZone);
- #else
- if(patch) {
- CalcMenuSizeUPP = NGetTrapAddress(_CalcMenuSize,ToolTrap);
- NSetTrapAddress((UniversalProcPtr)myCalcMenuSize,_CalcMenuSize,ToolTrap);
- }
- else {
- NSetTrapAddress(CalcMenuSizeUPP,_CalcMenuSize,ToolTrap);
- }
- #endif
- }
-
- //==================================================================================
- // get the colors from MCEntry table for drawing the popUp menu
- //==================================================================================
-
- static void getMenuColors(short menuID, short menuItem,
- RGBColor *menuFore, RGBColor *menuBack)
- {
- MCEntryPtr mcPtr;
-
- menuBack->red = -1; // default to black on white
- menuBack->green = -1;
- menuBack->blue = -1;
- menuFore->red = 0;
- menuFore->green = 0;
- menuFore->blue = 0;
-
- mcPtr = GetMCEntry(menuID,menuItem); // does this item have a color?
- if(mcPtr != 0L) {
- BlockMove(&mcPtr->mctRGB4,menuBack,sizeof(RGBColor));
- BlockMove(&mcPtr->mctRGB2,menuFore,sizeof(RGBColor));
- }
- else {
- mcPtr = GetMCEntry(menuID,0); // nope, try this menu
- if(mcPtr != 0L) {
- BlockMove(&mcPtr->mctRGB4,menuBack,sizeof(RGBColor));
- BlockMove(&mcPtr->mctRGB3,menuFore,sizeof(RGBColor));
- }
- else {
- mcPtr = GetMCEntry(0,0); // nope, try the menubar
- if(mcPtr != 0L) {
- BlockMove(&mcPtr->mctRGB2,menuBack,sizeof(RGBColor));
- BlockMove(&mcPtr->mctRGB3,menuFore,sizeof(RGBColor));
- }
- }
- }
- }
-
- //==================================================================================
- // restore the MCEntries for menu - call to Delete menu wiped 'em out
- //==================================================================================
- static void setMenuColors(short menuID)
- {
- short cnt;
- Handle hMctb;
-
- hMctb=Get1Resource('mctb', menuID);
- if(hMctb) {
- cnt=(GetHandleSize(hMctb)-sizeof(short))/sizeof(MCEntry);
- HLock(hMctb);
- SetMCEntries(cnt, (MCTablePtr)((*(char **)hMctb)+sizeof(short)));
- HUnlock(hMctb);
- ReleaseResource(hMctb);
- }
- }
-
- //==================================================================================
- // Set font for control drawing & force rebuild of font cache
- //==================================================================================
-
- static Boolean setFont(GrafPtr thisPort, short *saveFont, short *saveSize,
- short varCode, Boolean hasColorQD)
- {
- Boolean sysFont = false;
- GrafPtr currPort, wMgrPort;
- CGrafPtr wMgrCPort;
-
- if(varCode & popupUseWFont) { // use current port's font & size
-
- //----------------------------------------------------------------------------------
- // Set the textSize and textFont of current window manager port to defaults.
- // This is a work-around against some misbehaved apps from MicroSoft and Claris.
- // Thanks to Rick Christianson for this fix.
- //----------------------------------------------------------------------------------
-
- GetPort(&currPort);
-
- if (hasColorQD) {
- GetCWMgrPort(&wMgrCPort);
- SetPort((GrafPtr)wMgrCPort);
- }
- else {
- GetWMgrPort(&wMgrPort);
- SetPort(wMgrPort);
- }
- TextSize(0);
- TextFont(0);
-
- SetPort(currPort);
-
- if(thisPort->txFont == systemFont)
- sysFont = true;
- *saveFont = LMGetSysFontFam(); // save current system font number
- *saveSize = LMGetSysFontSize(); // save current system font size
- LMSetSysFontFam(thisPort->txFont); // set to the current port settings
- LMSetSysFontSize(thisPort->txSize);
- LMSetLastSPExtra(-1L); // force rebuild of font cache
- }
- else { // use system font & size
- sysFont = true;
- *saveFont = thisPort->txFont; // save current font & size
- *saveSize = thisPort->txSize;
- thisPort->txFont = LMGetSysFontFam();
- thisPort->txSize = LMGetSysFontSize();
- }
- return(sysFont); // getRects wants to know…
- }
-
- //==================================================================================
- // Restore font & force rebuild of font cache
- //==================================================================================
-
- static void restoreFont(GrafPtr thisPort, short saveFont, short saveSize, short varCode)
- {
- if(varCode & popupUseWFont) { // restore system font & size info
- LMSetSysFontFam(saveFont);
- LMSetSysFontSize(saveSize);
- LMSetLastSPExtra(-1L); // force rebuild of font cache
- }
- else { // restore current port settings
- thisPort->txFont = saveFont;
- thisPort->txSize = saveSize;
- }
- }
-
- //==================================================================================
- // return the size of the icon for a menu item, regardless of type.
- // returns TRUE if icon is a 'cicn'.
- //==================================================================================
- static void getIconSize(short iconNum, Rect *rIcon)
- {
- Handle hIcon=0;
-
- iconNum+=256;
-
- hIcon = GetResource('cicn', iconNum); // try for a color icon
- if(hIcon) {
- *rIcon = (**(PixMapHandle)hIcon).bounds; // could be any size…
- ReleaseResource(hIcon);
- }
- }
- //==================================================================================
- // Plot an icon of any type or size
- //==================================================================================
- static void plotAnIcon(short iconNum, Rect *rIcon, short osVers, short cmdChar,
- Boolean inactive, Boolean hasColorQD, Boolean inColor)
- {
- char state;
- Boolean isSICN=false;
- BitMap iBits;
- Handle hIcon=0;
- CIconHandle hCIcon;
- GrafPtr thisPort;
-
- //----------------------------------------------------------------------------------
- // Initialize
- //----------------------------------------------------------------------------------
- iconNum += 256; // MenuMgr weirdness…
- if(cmdChar == 0x1E)
- isSICN = true;
-
- if(isSICN) {
- hIcon = GetResource('SICN', iconNum);
- }
- else {
- if(hasColorQD) {
- hCIcon = GetCIcon(iconNum); // try for color icon first
- if(hCIcon) { // got it!
- if(inColor && osVers >= 0x0700) // use new routine
- PlotCIconHandle(rIcon, 0, (short)inactive, hCIcon);
- else
- PlotCIcon(rIcon, hCIcon); // original routine
-
- DisposCIcon(hCIcon);
- return; // all done…
- }
- }
- hIcon = GetResource('ICON', iconNum); // fall back to B&W icon
- }
-
- //----------------------------------------------------------------------------------
- // if we get to here, we are plotting an ICON, reduced ICON or SICN.
- //----------------------------------------------------------------------------------
- if(hIcon) {
- GetPort(&thisPort); // draw in correct port
- state = HGetState(hIcon);
- HLock(hIcon);
-
- //----------------------------------------------------------------------------------
- // Use the nifty new Icon utilities if we can. This has a nice advantage under
- // System 7 - the icon data is centered in the destination rect.
- //----------------------------------------------------------------------------------
- if(osVers >= 0x0700) {
- if(isSICN)
- PlotSICNHandle(rIcon, atAbsoluteCenter, ttNone, hIcon);
- else
- PlotIconHandle(rIcon, atAbsoluteCenter, ttNone, hIcon);
- }
- else {
- //----------------------------------------------------------------------------------
- // Well, since we don't have the new Icon utilities, do it by hand with CopyBits.
- // We won't get the nice centering of SICN and ICON data. A nice tight routine
- // is needed…
- //
- // Set up our bitmap for the correct icon size -
- //----------------------------------------------------------------------------------
-
- iBits.baseAddr = *hIcon;
- if(isSICN) {
- iBits.rowBytes = 2;
- SetRect(&iBits.bounds, 0, 0, 16, 16);
- }
- else {
- iBits.rowBytes = 4;
- SetRect(&iBits.bounds, 0, 0, 32, 32);
- }
-
- //----------------------------------------------------------------------------------
- // Now, blit it onscreen.
- //----------------------------------------------------------------------------------
-
- CopyBits( &iBits,
- &thisPort->portBits,
- &iBits.bounds,
- rIcon,
- srcCopy, nil);
- }
- HSetState(hIcon, state);
- ReleaseResource(hIcon);
- }
- }
-
- //==================================================================================
- // Check for ColorQuickDraw - see qdCDEF.c if you need the version of ColorQD
- //==================================================================================
- Boolean hasColorQD()
- {
- OSErr err;
- long gResult;
-
- if(trapAvailable(_Gestalt)) {
- err = Gestalt(gestaltQuickdrawVersion,&gResult);
- if(err == noErr)
- if(LoWord(gResult) >= gestalt8BitQD)
- return(true);
- }
- return(false);
- }